package logic;

import interfaces.Observer;

import java.io.ObjectInputStream.GetField;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Queue;

import constants.MessageType;
import android.util.Log;
import android.util.Pair;
import models.Mushroom;
import models.PhysicalObject;
import models.Wolf;

/**
 * This class handles recycling of objects and spawning parameters of new
 * objects
 * 
 * @author Knut, Stian
 * 
 */
public class SpawnAndDespawner implements java.util.Observer {

	/*
	 * TAG = the class name used for logging purposes readyWolves = the list of
	 * wolves ready for spawning readyMushrooms = the list of mushrooms ready
	 * for spawning wolves = the list of wolves mushrooms = the list of
	 * mushrooms
	 * 
	 * NOT USED: difficultyWave = an integer determining difficulty
	 */

	private static final String TAG = SpawnAndDespawner.class.getSimpleName();

	private Queue<Wolf> readyWolves = new LinkedList<Wolf>();
	private Queue<Mushroom> readyMushrooms = new LinkedList<Mushroom>();
	private ArrayList<PhysicalObject> list;
	private long lastSpawnW = 0;
	private long lastSpawnM = 0;
	private int difficulty;

	// private int difficultyWave;

	public SpawnAndDespawner(ArrayList<PhysicalObject> list, int difficulty) {
		this.difficulty = difficulty;
		this.list = list;

		/*
		 * Sort the list into a separate list for the wolves and the mushrooms
		 * Also add the objects to their respective ready queues
		 */
		for (PhysicalObject o : list) {
			if ((o instanceof Wolf)) {
				readyWolves.add((Wolf) o);
			} else if (o instanceof Mushroom) {
				readyMushrooms.add((Mushroom) o);
			}

			for (PhysicalObject ob : list) {
				ob.addObserver(this);
			}

		}
		Log.d(TAG, "SpawnAndDespawner created");
	}

	public void addToReady(PhysicalObject ob) {
		if (ob instanceof Wolf) {
			readyWolves.add((Wolf) ob);
		} else if (ob instanceof Mushroom) {
			readyMushrooms.add((Mushroom) ob);
		}
	}

	/**
	 * recursive function which spawns wolves.
	 * 
	 * @param wolves
	 * @param difficulty
	 * @param movement
	 * 
	 */

	public void spawnWolfTest() {

		/*
		 * Check if there are any wolves ready to be spawned (IS THE
		 * MATH.RANDOM() USED TO PREVENT INSTANT RESPAWN?)
		 */
		if (readyWolves.size() == 0)
			return;

		// This parameter can be edited to change the difficulty
		if ((lastSpawnW >= System.currentTimeMillis()
				- (1000 * difficulty + 1000 * Math.random())))
			return;

		/*
		 * Get the next wolf from the queue.
		 */
		Wolf wolf = readyWolves.poll();

		/*
		 * Set movement pattern, velocity and acceleration
		 */
		wolf.setMovementPattern((int) (Math.random() * 2));
		wolf.getMotion().setHorizontalAcceleration(0);
		wolf.getMotion().setVerticalAcceleration(0);
		wolf.getMotion().setHorizontalVelocity(-2 - ((int) Math.random() * 3));
		wolf.getMotion().setVerticalVelocity(0);

		/*
		 * Set position of the wolf, horizontal position just outside the right
		 * side of the screen and vertical position a random number between 0
		 * and the view height
		 */
		wolf.setHorizontalPosition(wolf.getScreenWidth());
		wolf.setVerticalPosition((int) (Math.random() * wolf.getScreenHeight()));

		/*
		 * Reactivate the wolf
		 */
		wolf.setActive(true);
		lastSpawnW = System.currentTimeMillis();
	}

	public void spawnMushroomTest() {

		/*
		 * Check if there are any mushrooms ready to be spawned
		 */
		if (readyMushrooms.size() == 0)
			return;

		if ((lastSpawnM >= System.currentTimeMillis()
				- (1500 + 1000 * Math.random()))) // Kan endres for vanskelighet
			return;
		/*
		 * Get the next mushroom from the queue.
		 */
		Mushroom mushroom = readyMushrooms.poll();

		/*
		 * Set movement pattern, velocity and acceleration
		 */
		mushroom.getMotion().setHorizontalAcceleration(0);
		mushroom.getMotion().setVerticalAcceleration(0);
		mushroom.getMotion().setHorizontalVelocity(-2);
		mushroom.getMotion().setVerticalVelocity(0);

		/*
		 * Set position of the mushroom, horizontal position just outside the
		 * right side of the screen and vertical position a random number
		 * between 0 and the view height. mushroom.getScreenWidth()
		 */
		mushroom.setHorizontalPosition(mushroom.getScreenWidth());
		mushroom.setVerticalPosition((int) (Math.random() * mushroom
				.getScreenHeight()));

		/*
		 * Reactivate the mushroom
		 */
		mushroom.setActive(true);
		lastSpawnM = System.currentTimeMillis();
	}

	private void resetObjects() {
		for (PhysicalObject o : list) {
			if (o instanceof Wolf || o instanceof Mushroom) {
				o.setActive(false);
			}
		}
	}

	@Override
	public void update(Observable observable, Object data) {

		if (data instanceof Pair) {
			@SuppressWarnings({ "rawtypes", "unchecked" })
			Pair<PhysicalObject, MessageType> pair = (Pair) data;
			PhysicalObject ob = pair.first;
			MessageType mt = pair.second;

			switch (mt) {
			case OUTSIDEVIEW:

				addToReady(ob);
				break;
			case POISONMUSHROOMHIT:

				addToReady(ob);
				break;
			case SPARKLEMUSHROOMHIT:

				addToReady(ob);
				break;
			case COLLISION:

				// Resetter ulver/mushrooms
				resetObjects();
				// set flag to stop spawning
				break;
			}

		}
	}

}
